if not HST then return end

-- Hold a period of time to show the cast result (success, failed or interrupted)
HST.StateHoldTime = 1

-- Castbar fades out when the cast has stopped, failed or interrupted
HST.FadeHoldTime = 0.1

HST.FadeAlpha = 0.6

HST.NormalAlpha = 0.9

function HST:CastBarInit()
	CastingBarFrame:Hide()

	self.CastBar = CreateFrame("Frame", "HSTBarFrame", UIParent)
	self.CastBar:SetFrameStrata("MEDIUM")
	self.CastBar:SetClampedToScreen(true)

	self.CastBar.Texture = self.CastBar:CreateTexture("HSTBarFrameTexture","OVERLAY")
	self.CastBar.IconTexture = self.CastBar:CreateTexture("HSTBarFrameIconTexture", "OVERLAY")

	self.CastBar.Message = self.CastBar:CreateFontString("HSTBarText", "OVERLAY")
	self.CastBar.Message:SetFontObject(GameFontHighlightSmall)
	self.CastBar.Message:SetJustifyH("LEFT")

	self.CastBar.Background = self.CastBar:CreateTexture(nil,"ARTWORK")
	self.CastBar.Background:SetTexture(45/100, 45/100, 45/100, 0.6)
	self.CastBar.Background:SetAllPoints(self.CastBar)

	self.CastBar.Border = self.CastBar:CreateTexture(nil,"BORDER")
	self.CastBar.Border:SetPoint("CENTER",self.CastBar,"CENTER")	
	self.CastBar.Border:SetTexture(0,0,0)

	self.CastBar.BorderBackground = self.CastBar:CreateTexture(nil,"BACKGROUND")
	self.CastBar.BorderBackground:SetPoint("CENTER", self.CastBar, "CENTER")
	self.CastBar.BorderBackground:SetTexture(1,1,1)
end

function HST:OnCastBarProfileEnabled() 
	local x = HST.db.profile.x
	local y = HST.db.profile.y
	local height = HST.db.profile.castBarHeight
	local width = HST.db.profile.width

	self.CastBar:SetAlpha(HST.db.profile.alpha)
	self.CastBar:SetWidth(width)
	self.CastBar:SetHeight(height)
	self.CastBar:ClearAllPoints()

	self.CastBar:SetPoint("CENTER", UIParent, "CENTER", 0, -376)

	self.CastBar.IconTexture:SetWidth(height)
	self.CastBar.IconTexture:SetHeight(height)
	self.CastBar.IconTexture:SetPoint("LEFT", self.CastBar, "LEFT")

	self.CastBar.Texture:SetHeight(height)
	self.CastBar.Texture:SetWidth(width - height - HST.db.profile.border)
	self.CastBar.Texture:SetTexture("Interface\\AddOns\\HST\\media\\"..HST.db.profile.timertexture)
	self.CastBar.Texture:SetPoint("LEFT", self.CastBar, "LEFT", height + HST.db.profile.border, 0)

	self.CastBar.Message:SetHeight(height)
	self.CastBar.Message:SetWidth(width - height - HST.db.profile.border)
	self.CastBar.Message:SetPoint("LEFT", self.CastBar.IconTexture, "LEFT", height + HST.db.profile.border, 0)

	self.CastBar.Border:SetWidth(width + 2)
	self.CastBar.Border:SetHeight(height + 2)

	self.CastBar.BorderBackground:SetWidth(width + (HST.db.profile.border * 1.5))
	self.CastBar.BorderBackground:SetHeight(height + (HST.db.profile.border * 1.5))
	self.CastBar.BorderBackground:SetVertexColor(
        HST.db.profile.colors.bordercolor.r,
        HST.db.profile.colors.bordercolor.g,
        HST.db.profile.colors.bordercolor.b)

	self.CastBar.Texture:SetVertexColor(
		HST.db.profile.colors.castingColor.r,
		HST.db.profile.colors.castingColor.g,
		HST.db.profile.colors.castingColor.b)

	self.CastBar:SetAlpha(0)
end

function HST:ShowCastBar(SpellName, Icon, CastTime, StartTime)
	self:ShowDefaultCastBar(SpellName, Icon, CastTime, StartTime)
end

function HST:ShowChannelCastBar(SpellName, Icon, CastTime, StartTime)
	self:ShowDefaultCastBar(SpellName, Icon, CastTime, StartTime, true)
end

function HST:ShowDefaultCastBar(SpellName, Icon, CastTime, StartTime, Channel)
	local _,_,latency = GetNetStats()
	self.castblock = true
	self.casting = true	
	self.casttime = CastTime + (latency / 1000)
	self.castStart = StartTime
	self.spellName = SpellName

	if not Channel then
		self.channeling = nil
	else
		self.channeling = Channel
	end
	
	self.CastBar.Texture:SetVertexColor(
		HST.db.profile.colors.castingColor.r,
		HST.db.profile.colors.castingColor.g,
		HST.db.profile.colors.castingColor.b)

	self.CastBar.IconTexture:SetTexture(Icon)
	self.CastBar:SetAlpha(self.NormalAlpha)
	self.CastBar:Show()
	self:CancelCastBarUpdateEvent()
	self:SendCastBarUpdateEvent()
end

function HST:CastBarOnEvent(event, arg1, arg2)
	if event == "HST_ON_CAST_BAR_UPDATE" then
		self:HandleCastBarUpdate()
	elseif event == "SPELLCAST_START" then
		self:HandleCastStart(arg1, arg2)
	elseif event == "SPELLCAST_CHANNEL_START" then
		self:HandleChannelCastStart(arg1, arg2)
	elseif event == "SPELLCAST_CHANNEL_UPDATE" then
		self:HandleChannelCastUpdate(arg1)
	elseif event == "SPELLCAST_CHANNEL_STOP" then
		HST:HandleChannelCastStop()
	elseif event == "SPELLCAST_STOP" then
		self:HandleCastStop()
	elseif event == "SPELLCAST_INTERRUPTED" then
		self:HandleCastInterrupted()
	elseif event == "SPELLCAST_FAILED" then
		self:HandleCastFailed()
	elseif event == "SPELLCAST_DELAYED" then
		self:HandleCastDelayed(arg1)
	elseif event == "ITEM_LOCK_CHANGED" then
		return self:HandleCastBarItemLockChanged()
	end
end

function HST:HandleCastBarUpdate()
	if not self.casting then return end

	local process = self:GetCastProcess()
	local height = HST.db.profile.castBarHeight
	local width = HST.db.profile.width
	local w = width - height - HST.db.profile.border

	local current = 0 
	if self.channeling then current = 1 - process else current = process end
	self.CastBar.Texture:SetWidth(w * current)

	if self.casttime then 
		local time = self:Regulate(self.castStart + self.casttime - GetTime(), 0.01)
		if not self.displayTime or time >= 0 and self.displayTime - time >= 0.01 then
			self.displayTime = time
			self.CastBar.Message:SetText(self.spellName .. " (" .. self:Regulate(self.displayTime) .. "s)")
		end
	end
end

function HST:HasCastStarted()
	return self.casting
end

function HST:GetCastProcess()
	if not self.castStart or not self.casttime then return 0 end
	local r = (GetTime() - self.castStart) / self.casttime
	return math.max(math.min(r, 1), 0)
end

function HST:ShouldFadeOut()
	return not self.casttime or self.castStart + self.casttime - GetTime() < self.FadeHoldTime 
end

function HST:HandleCastStart(SpellName, CastTime)
	local icon = self:GetSpellIcon(SpellName)
	if icon then 
		HST:HideBlizzardCastBar()
		local casttime = self:GetCastTimeByHaste(CastTime / 1000)
		self:ShowCastBar(SpellName, icon, casttime, GetTime())
	end
end

function HST:HandleChannelCastStart(CastTime)
	HST:HideBlizzardCastBar()
	HST:ShowChannelCastBar("治疗宠物", self:GetSpellIcon("治疗宠物"), 
		self:GetCastTimeByHaste(CastTime / 1000), GetTime())
end

function HST:HandleChannelCastUpdate(arg1)
	
end

function HST:HandleChannelCastStop()
	self:HandleCastStop()
end

function HST:ResetCastBar()
	self.castblock = nil
	self.casting = nil	
	self.casttime = nil
	self.castStart = nil
	self.channeling = nil
	self.displayTime = nil
	self.CastBar:Hide()
	self:CancelCastBarUpdateEvent()
end

function HST:HandleCastStop()
	self:ResetCastBar()
	self.CastBar.Texture:SetVertexColor(
		HST.db.profile.colors.castDoneColor.r,
		HST.db.profile.colors.castDoneColor.g,
		HST.db.profile.colors.castDoneColor.b)
end

function HST:HandleCastInterrupted()
	self:HandleCastError()
end

function HST:HandleCastFailed()
	self:HandleCastError()
end

function HST:HandleCastError(Message)
	self:ResetCastBar()
	self.CastBar.Texture:SetVertexColor(
		HST.db.profile.colors.castFailColor.r,
		HST.db.profile.colors.castFailColor.g,
		HST.db.profile.colors.castFailColor.b)
end

function HST:HandleCastDelayed(Delayed)
	if self.casttime then self.casttime = self.casttime + Delayed / 1000 end
end

function HST:HandleCastBarItemLockChanged()
	if self.casting then
		self.casting = nil
		self.casttime = nil
		self.castblock = nil
		self.displayTime = nil
		return 1
	end
	return nil
end

function HST:HideBlizzardCastBar()
	CastingBarFrame:Hide()
end

function HST:Regulate(Time, format)
	if type(Time) ~= "number" then return 0.00 end
	if not format then format = 0.01 end
	return Time - math.mod(Time, format)
end